home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir34 / thindi.zip / THISRC.ZIP / STATBAR.C < prev    next >
C/C++ Source or Header  |  1994-01-19  |  21KB  |  602 lines

  1. //===========================================================
  2. // StatBar - A set of routines that adds a status bar to a
  3. // client window.
  4. // Copyright (C) 1993 Douglas Boling
  5. //
  6. //    To Use:
  7. //   Include Statbar.h in source file
  8. //
  9. //
  10. //
  11. // Revision History:
  12. //
  13. // 1.0   Initial Release
  14. //===========================================================
  15. // Returns no. of elements
  16. #define dim(x) (sizeof(x) / sizeof(x[0]))   
  17.  
  18. #include "windows.h"
  19. #include "string.h"
  20. #include "stdlib.h"
  21.  
  22. #define INT       int
  23. #define UINT      WORD
  24. #define APIENTRY  PASCAL
  25. #define WNDPROC   FARPROC
  26.  
  27. #include "statbar.h"
  28.  
  29. #define TEXTBUFFSIZE   512
  30.  
  31. struct decodeUINT {                         // structure associates
  32.     UINT Code;                              // messages 
  33.     LONG (*Fxn)(HWND, UINT, UINT, LONG);    // with a function
  34. }; 
  35. typedef struct {
  36.     INT sWidth;
  37.     char far *lpszText;
  38. } FIELDENT;
  39. typedef struct {
  40.     HFONT    hFont;
  41.     INT    sHeight;
  42.     LPSTR lpEnd;
  43.     INT    sFreeSpace;
  44.     INT    sNumFields;
  45.     FIELDENT feField[1];
  46. } STATUSBARDATA;
  47. typedef STATUSBARDATA far * LPSTATUSBARDATA;
  48.  
  49. //-----------------------------------------------------------
  50. // NonPublic procedure declarations
  51. //----------------------------------------------------------
  52. // Message handler functions for client subclass proc
  53. LONG DoSizeClient (HWND, UINT, UINT, LONG);
  54. LONG DoMenuSelectClient (HWND, UINT, UINT, LONG);
  55. LONG DoDestroyClient (HWND, UINT, UINT, LONG);
  56. // Message handler functions for status bar window proc
  57. LONG DoSetTextStatBar (HWND, UINT, UINT, LONG);
  58. LONG DoGetTextStatBar (HWND, UINT, UINT, LONG);
  59. LONG DoPaintStatBar (HWND, UINT, UINT, LONG);
  60. //LONG DoSizeStatBar (HWND, UINT, UINT, LONG);
  61. LONG DoDestroyStatBar (HWND, UINT, UINT, LONG);
  62. //Status bar functions
  63. HFONT GetStatusBarFont (void);
  64. void GetFieldRect (LPSTATUSBARDATA, INT, RECT *, RECT *);
  65. void DrawFieldText (LPSTATUSBARDATA, HWND, LPSTR, RECT *);
  66. void DrawSBText (HWND, char far *, INT);
  67. void Draw3DRect (HDC, HPEN, HPEN, RECT *);
  68.  
  69. // Utility routines
  70. WNDPROC MySubClassWindow (HWND, WNDPROC);
  71.  
  72. //-----------------------------------------------------------
  73. // Global data
  74. //-----------------------------------------------------------
  75. // Message dispatch table for ClientSCProc
  76. struct decodeUINT ClientSCMessages[] = {
  77.     WM_SIZE, DoSizeClient,
  78.     WM_MENUSELECT, DoMenuSelectClient,
  79.     WM_DESTROY, DoDestroyClient,
  80. };
  81. // Message dispatch table for StatbarWndProc
  82. struct decodeUINT StatBarMessages[] = {
  83.     WM_SETTEXT, DoSetTextStatBar,
  84.     WM_GETTEXT, DoGetTextStatBar,
  85.     WM_PAINT, DoPaintStatBar,
  86.     WM_DESTROY, DoDestroyStatBar,
  87. };
  88. HANDLE    hInst;
  89. FARPROC lpfnClientSCProc, lpfnOldClientWndProc;
  90. //============================================================
  91. // Status Bar Public functions
  92. //============================================================
  93. //-----------------------------------------------------------
  94. // StatusBarInit - Initialization code for the status bar.
  95. //-----------------------------------------------------------
  96. INT StatusBarInit(HANDLE hInstance) {
  97.     WNDCLASS     wc;
  98.  
  99.     hInst = hInstance;
  100.     //
  101.     // Register status bar window class
  102.     //
  103.     wc.style = CS_HREDRAW;                    // Class style
  104.     wc.lpfnWndProc = StatBarWinProc;          // Callback function
  105.     wc.cbClsExtra = 0;                        // Extra class data
  106.     wc.cbWndExtra = sizeof (HGLOBAL);         // Extra window data
  107.     wc.hInstance = hInst;                     // Owner handle
  108.     wc.hIcon = 0;                             // Application icon
  109.     wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Default cursor
  110.     wc.hbrBackground = CreateSolidBrush (GetSysColor (COLOR_BTNFACE));
  111.     wc.lpszMenuName =  0;                     // Menu name
  112.     wc.lpszClassName = "StatusBarCls";        // Window class name
  113.     if (RegisterClass(&wc) == 0)
  114.         return 1;
  115.         
  116.         
  117.     return 0;
  118. }
  119. //-----------------------------------------------------------
  120. // StatusBarCreate - Creates a status bar window
  121. //-----------------------------------------------------------
  122. INT StatusBarCreate (HWND hWndClient, INT sNumFields, INT *sFieldArray) {
  123.    INT x, y, cx, cy;
  124.     HWND hwndStatBar;
  125.     RECT rect;
  126.     HGLOBAL hData;
  127.     LPSTATUSBARDATA lpStatData;
  128.     //
  129.     //Alloc memory for status window info block
  130.     //
  131.     hData = GlobalAlloc (GHND, sizeof (STATUSBARDATA) + 
  132.                          sNumFields * sizeof(FIELDENT) +
  133.                          TEXTBUFFSIZE);
  134.     if (!hData)
  135.         return 11;
  136.     lpStatData = (LPSTATUSBARDATA) GlobalLock (hData);
  137.     //
  138.     //Init memory block
  139.     //
  140.     lpStatData->sFreeSpace = TEXTBUFFSIZE; 
  141.     lpStatData->lpEnd = (LPSTR) lpStatData + sizeof (STATUSBARDATA) + 
  142.                        sNumFields * sizeof(FIELDENT);
  143.     lpStatData->sNumFields = sNumFields;
  144.     
  145.     for (x = 0; x < sNumFields; x++) {
  146.         lpStatData->feField[x].sWidth = sFieldArray[x];
  147.         lpStatData->feField[x].lpszText = 0;
  148.     }    
  149.     //
  150.     //Create the status bar font
  151.     //
  152.     lpStatData->hFont = GetStatusBarFont ();
  153.     lpStatData->sHeight = GetStatusBarHeight ();
  154.     //                                    
  155.     // Create status bar window
  156.     //
  157.     GetClientRect (hWndClient, &rect);
  158.     x = rect.left;
  159.     y = rect.bottom - lpStatData->sHeight;
  160.     cx = rect.right - rect.left;
  161.     cy = lpStatData->sHeight;
  162.     hwndStatBar = CreateWindow ("StatusBarCls", NULL, 
  163.                                WS_CHILD | WS_VISIBLE, x, y, cx, cy, 
  164.                                hWndClient, IDD_STATBAR, hInst, NULL);
  165.  
  166.     if(!hwndStatBar) {
  167.         OutputDebugString ("Status Bar create fail\n");    
  168.         return 0x10;
  169.     }
  170.     SetWindowWord (hwndStatBar, 0, hData);
  171.     GlobalUnlock (hData);
  172.  
  173.     lpfnClientSCProc = MakeProcInstance ((FARPROC) ClientSCProc, hInst);
  174.     lpfnOldClientWndProc = MySubClassWindow (hWndClient, lpfnClientSCProc);
  175.     return 0;                         // return success flag
  176. }
  177. //------------------------------------------------------------
  178. // GetStatusBarHeight - returns the height of the status bar
  179. //------------------------------------------------------------
  180. INT GetStatusBarHeight (void) {
  181.     HDC hdc;
  182.     HFONT hFont, hOld;
  183.     TEXTMETRIC tm;
  184.     //
  185.     //Create the status bar font and compute its size
  186.     //
  187.     hFont = GetStatusBarFont ();
  188.     hdc = GetDC(NULL);
  189.     hOld = SelectObject(hdc, hFont);
  190.     GetTextMetrics(hdc, &tm);
  191.     SelectObject(hdc, hOld);
  192.     DeleteObject (hFont);
  193.     ReleaseDC(NULL, hdc);
  194.     return tm.tmHeight + tm.tmExternalLeading + 10;
  195. }
  196. //------------------------------------------------------------
  197. // ModifyClientRect - Modifies a rect structure filled with
  198. // the client window dimentions to reflect the status bar
  199. //------------------------------------------------------------
  200. INT ModifyClientRect (HWND hWnd, RECT *rectOut) {
  201.     RECT rect;
  202.     HWND hwndStatBar;
  203.  
  204.     hwndStatBar = GetDlgItem (hWnd, IDD_STATBAR);
  205.     if (hwndStatBar == 0)
  206.         return 0;
  207.     GetClientRect (hwndStatBar, &rect);
  208.     rectOut->bottom -= (rect.bottom - rect.top);
  209.     return 0;
  210. }
  211. //------------------------------------------------------------
  212. // SetStatusBarLong - Displays a number in a status bar field
  213. // status bar.
  214. //------------------------------------------------------------ 
  215. INT SetStatusBarLong (HWND hWnd, char *pszText, LONG lNum, INT sField) {
  216.     char szTemp[256];
  217.     
  218.     strcpy (szTemp, pszText);
  219.     ltoa (lNum, &szTemp[strlen(szTemp)], 10);
  220.     return SetStatusBarText (hWnd, szTemp, sField);
  221. }
  222. //------------------------------------------------------------
  223. // SetStatusBarText - Sets the texts for a field in the 
  224. // status bar.
  225. //------------------------------------------------------------ 
  226. INT SetStatusBarText (HWND hWnd, char *pszText, INT sField) {
  227.     HWND hwndStatBar;
  228.     LPSTATUSBARDATA lpStatData;
  229.     INT i, sLen, sSrcLen;
  230.     LPSTR lpSrc; 
  231.     LPSTR lpDest;
  232.     
  233.     hwndStatBar = GetDlgItem (hWnd, IDD_STATBAR);
  234.     if (hwndStatBar == 0)
  235.         return 1;
  236.  
  237.     lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hwndStatBar, 0));
  238.     //
  239.     //Copy the text into the status bar global buffer
  240.     //        
  241.     if (lpStatData->feField[sField].lpszText != 0) {
  242.         //
  243.         //If field already has text, remove and collapse the buffer
  244.         //strings over the string being removed.        
  245.         //
  246.         lpDest = lpStatData->feField[sField].lpszText;
  247.         sLen = lstrlen (lpDest) + 1;
  248.         lpSrc = lpDest + sLen;
  249.         while (lpSrc < lpStatData->lpEnd) {
  250.             //
  251.             //Search array for pointer to this string
  252.             //
  253.             for (i = 0; i < lpStatData->sNumFields; i++)  
  254.                 if (lpSrc == lpStatData->feField[i].lpszText)
  255.                     break;
  256.             //
  257.             //Move string and update pointer.
  258.             //
  259.             lpStatData->feField[i].lpszText = lpDest;
  260.             lstrcpy (lpDest, lpSrc);
  261.             sSrcLen = lstrlen (lpSrc) + 1;
  262.             lpDest += sSrcLen;
  263.             lpSrc += sSrcLen;
  264.         }
  265.         lpStatData->lpEnd = lpDest;
  266.         lpStatData->sFreeSpace += sLen;
  267.     }        
  268.     sLen = strlen (pszText) + 1;
  269.     if (sLen < lpStatData->sFreeSpace) {
  270.         lstrcpy (lpStatData->lpEnd, pszText);
  271.         lpStatData->feField[sField].lpszText = lpStatData->lpEnd;
  272.         lpStatData->lpEnd += sLen;
  273.         lpStatData->sFreeSpace -= sLen;
  274.     } else
  275.         return 2;
  276.     return DrawSBText (hwndStatBar, pszText, sField);    
  277. }
  278. //============================================================
  279. // Client window subclass procedures
  280. //============================================================
  281. //------------------------------------------------------------
  282. // ClientSCProc - Callback subclass function for client window
  283. //------------------------------------------------------------
  284. LONG CALLBACK ClientSCProc(HWND hWnd, UINT wMsg, UINT wParam, 
  285.                            LONG lParam) {
  286.     INT i;
  287.     //
  288.     // Search message list to see if we need to handle this
  289.     // message.  If in list, call procedure.
  290.     //
  291.     for(i = 0; i < dim(ClientSCMessages); i++) {
  292.         if(wMsg == ClientSCMessages[i].Code)
  293.             return (*ClientSCMessages[i].Fxn)(hWnd, wMsg, wParam, lParam);
  294.     }
  295.     return CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg,
  296.                            wParam, lParam);
  297. }
  298. //------------------------------------------------------------
  299. // DoSizeClient - process WM_SIZE message for client window.
  300. //------------------------------------------------------------ 
  301. LONG DoSizeClient (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  302.     
  303.    INT x,y, cx, cy;
  304.     RECT rect;
  305.     LPSTATUSBARDATA lpStatData;
  306.     HGLOBAL hData;
  307.     HWND hwndStatBar;
  308.  
  309.     hwndStatBar = GetDlgItem (hWnd, IDD_STATBAR);
  310.     if (hwndStatBar == 0)
  311.         return CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg,
  312.                                wParam, lParam);
  313.     hData = GetWindowWord (hwndStatBar, 0);
  314.     lpStatData = (LPSTATUSBARDATA) GlobalLock (hData);
  315.  
  316.     // Compute size of window
  317.     GetClientRect (hWnd, &rect);
  318.     x = rect.left;
  319.     y = rect.bottom - lpStatData->sHeight;
  320.     cx = rect.right - rect.left;
  321.     cy = lpStatData->sHeight;
  322.     SetWindowPos (hwndStatBar, NULL, x, y, cx, cy, SWP_NOZORDER);
  323.     GlobalUnlock (hData);    
  324.  
  325.     return CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg,
  326.                            wParam, lParam);
  327. }
  328. //------------------------------------------------------------
  329. // DoMenuSelectClient - process WM_MENUSELECT message for client window.
  330. //------------------------------------------------------------ 
  331. LONG DoMenuSelectClient (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  332.     HWND hwndStatBar;
  333.     char szText[128];
  334.     UINT usFlags, usMenu;
  335.     LPSTATUSBARDATA lpStatData;
  336.  
  337.     hwndStatBar = GetDlgItem (hWnd, IDD_STATBAR);
  338.     if (hwndStatBar == 0)
  339.         return CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg,
  340.                                wParam, lParam);
  341.     usFlags = LOWORD (lParam);
  342.     usMenu = wParam;
  343.     szText[0] = '\0';
  344.     
  345.     if ((usFlags & MF_SYSMENU) && (usMenu == NULL)) {
  346.         lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hwndStatBar, 0));
  347.         if (lpStatData->feField[0].lpszText)
  348.             DrawSBText (hwndStatBar, lpStatData->feField[0].lpszText, 0);
  349.         else     
  350.             DrawSBText (hwndStatBar, "", 0);
  351.         GlobalUnlock (GetWindowWord (hwndStatBar, 0));
  352.     } else if (!(usFlags & MF_SEPARATOR)) {
  353.         if ((usFlags & MF_SYSMENU) && (usFlags & MF_POPUP))
  354.             LoadString (hInst, IDM_SYSMENUACTIVE, szText, sizeof (szText));
  355.         else if (!(usFlags & MF_POPUP))
  356.             LoadString (hInst, usMenu+MENUTEXT, szText, sizeof (szText));
  357.             
  358.         DrawSBText (hwndStatBar, szText, 0);
  359.     }
  360.     return CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg,
  361.                            wParam, lParam);
  362. }    
  363. //------------------------------------------------------------
  364. // DoDestroyClient - process WM_DESTROY message for client window.
  365. //------------------------------------------------------------ 
  366. LONG DoDestroyClient (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  367.     LONG lRC;
  368.  
  369.     DestroyWindow (GetDlgItem (hWnd, IDD_STATBAR));
  370.     
  371.     lRC = CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg,
  372.                            wParam, lParam);
  373.  
  374.     MySubClassWindow (hWnd, lpfnOldClientWndProc);
  375.     FreeProcInstance ((FARPROC) lpfnClientSCProc);
  376.     
  377.     return lRC;
  378. }
  379. //============================================================
  380. // Status Bar Window functions
  381. //============================================================
  382. //------------------------------------------------------------
  383. // StatBarWinProc - Callback function for status bar window
  384. //------------------------------------------------------------
  385. LONG CALLBACK StatBarWinProc(HWND hWnd, UINT wMsg, UINT wParam, 
  386.                              LONG lParam) {
  387.     INT i;
  388.     //
  389.     // Search message list to see if we need to handle this
  390.     // message.  If in list, call procedure.
  391.     //
  392.     for(i = 0; i < dim(StatBarMessages); i++) {
  393.         if(wMsg == StatBarMessages[i].Code)
  394.             return (*StatBarMessages[i].Fxn)(hWnd, wMsg, wParam, lParam);
  395.     }
  396.     return DefWindowProc(hWnd, wMsg, wParam, lParam);
  397. }
  398. //------------------------------------------------------------
  399. // DoSetTextStatBar - process WM_SETTEXT message for StatBar window.
  400. // Place default text in field 0
  401. //------------------------------------------------------------ 
  402. LONG DoSetTextStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  403.     char szTemp[256];
  404.  
  405.     lstrcpyn (szTemp, (LPSTR) lParam, sizeof (szTemp) - 1);
  406.     szTemp[255] = '\0';
  407.     SetStatusBarText (GetParent (hWnd), szTemp, 0);
  408.     return 0;
  409. }
  410. //------------------------------------------------------------
  411. // DoGetTextStatBar - process WM_GETTEXT message for StatBar window.
  412. // Return text from field 0
  413. //------------------------------------------------------------ 
  414. LONG DoGetTextStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  415.     LPSTATUSBARDATA lpStatData;
  416.     UINT usLen;
  417.     LPSTR lpSrc; 
  418.     
  419.     lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0));
  420.     //
  421.     //Copy the text into the status bar global buffer
  422.     //        
  423.     usLen = 0;
  424.     if (lpStatData->feField[0].lpszText != 0) {
  425.         lpSrc = lpStatData->feField[0].lpszText;
  426.         usLen = min ((UINT)lstrlen (lpSrc), wParam-1);
  427.         lstrcpyn ((LPSTR) lParam, lpSrc, usLen);
  428.         *((LPSTR)lParam+usLen) = '\0';
  429.     }    
  430.     GlobalUnlock (GetWindowWord (hWnd, 0));
  431.     return usLen;
  432. }
  433. //------------------------------------------------------------
  434. // DoPaintStatBar - process WM_PAINT message for StatBar window.
  435. //------------------------------------------------------------ 
  436. LONG DoPaintStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  437.     INT i;
  438.     LPSTATUSBARDATA lpStatData;
  439.     HDC hdc;
  440.     PAINTSTRUCT ps;
  441.     RECT rect, rectOut;
  442.     HPEN hLPen, hDPen, hOldPen;
  443.  
  444.     lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0));
  445.     
  446.     GetClientRect (hWnd, &rect);
  447.     hdc = BeginPaint (hWnd, &ps);
  448.  
  449.     hDPen = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNSHADOW));
  450.     hLPen = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNHIGHLIGHT));
  451.     //
  452.     //Draw sep line across the top of the status bar
  453.     //    
  454.     hOldPen = SelectObject (hdc, hDPen);
  455.     MoveTo (hdc, rect.left, rect.top);
  456.     LineTo (hdc, rect.right, rect.top);
  457.     SelectObject (hdc, hLPen);
  458.     MoveTo (hdc, rect.left, rect.top+1);
  459.     LineTo (hdc, rect.right, rect.top+1);
  460.     SelectObject (hdc, hOldPen);
  461.     //
  462.     //Draw the individual fields
  463.     //
  464.     for (i = 0; i < lpStatData->sNumFields; i++) {
  465.         GetFieldRect (lpStatData, i, &rect, &rectOut);
  466.         Draw3DRect (hdc, hDPen, hLPen, &rectOut);
  467.         DrawFieldText (lpStatData, hWnd, lpStatData->feField[i].lpszText, 
  468.                        &rectOut);
  469.     }    
  470.     DeleteObject (hDPen);
  471.     DeleteObject (hLPen);
  472.     EndPaint (hWnd, &ps);
  473.     GlobalUnlock (GetWindowWord (hWnd, 0));
  474.     return 0;
  475. }
  476. //------------------------------------------------------------
  477. // DoDestroyStatBar - process WM_DESTROY message for status bar 
  478. // window.
  479. //------------------------------------------------------------ 
  480. LONG DoDestroyStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) {
  481.     LPSTATUSBARDATA lpStatData;
  482.  
  483.     lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0));
  484.     DeleteObject (lpStatData->hFont);            
  485.     GlobalUnlock (GetWindowWord (hWnd, 0));
  486.     GlobalFree (GetWindowWord (hWnd, 0));
  487.     return DefWindowProc(hWnd, wMsg, wParam, lParam);
  488. }
  489. //------------------------------------------------------------
  490. // GetStatusBarFont - returns a font handle for the status
  491. // bar font.
  492. //------------------------------------------------------------
  493. HFONT GetStatusBarFont (void) {
  494.     HDC hdc;
  495.    INT sFHeight;
  496.     //
  497.     //Create the status bar font and compute its size
  498.     //
  499.     hdc = GetDC(NULL);
  500.     sFHeight = MulDiv(-10, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  501.     ReleaseDC(NULL, hdc);
  502.     return CreateFont(sFHeight, 0, 0, 0, FW_BOLD, 0, 0, 0,
  503.                   ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  504.                   DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "Helv");
  505. }
  506. //------------------------------------------------------------
  507. // DrawFieldText - Draws text in a status bar field
  508. //------------------------------------------------------------ 
  509. void DrawFieldText (LPSTATUSBARDATA lpStatData, HWND hWnd, 
  510.                     LPSTR lpszText, RECT *rect) {
  511.     HDC hdc;
  512.     HFONT hOldFont;
  513.     
  514.     rect->top += 2;
  515.     rect->bottom -= 2;
  516.     rect->left += 5;
  517.     rect->right -= 5;
  518.  
  519.     hdc = GetDC (hWnd);        
  520.     hOldFont = SelectObject (hdc, lpStatData->hFont);
  521.     SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
  522.     SetBkColor (hdc, GetSysColor (COLOR_BTNFACE));
  523.     if (lpszText)
  524.         ExtTextOut (hdc, rect->left, rect->top, ETO_CLIPPED | ETO_OPAQUE,
  525.                     rect, lpszText, lstrlen (lpszText), NULL);
  526.     else                    
  527.         ExtTextOut (hdc, rect->left, rect->top, ETO_CLIPPED | ETO_OPAQUE,
  528.                     rect, "", 0, NULL);
  529.  
  530.     SelectObject (hdc, hOldFont);
  531.     ReleaseDC (hWnd, hdc);
  532.     return;
  533. }    
  534. //------------------------------------------------------------
  535. // GetFieldRect - Computes the rectangle for a given field.
  536. //------------------------------------------------------------ 
  537. void GetFieldRect (LPSTATUSBARDATA lpStatData, INT sField, 
  538.                    RECT *rect, RECT *rectOut) {
  539.     INT i, sRight;
  540.  
  541.     *rectOut = *rect;
  542.     rectOut->top += 3;
  543.     rectOut->bottom -= 3;
  544.     rectOut->left += 3;
  545.     rectOut->right -= 3;
  546.     sRight = rectOut->right;
  547.     
  548.     for (i = 0; i < sField; i++) 
  549.         if (lpStatData->feField[i].sWidth)
  550.             rectOut->left += lpStatData->feField[i].sWidth + 3;
  551.         else
  552.             break;
  553.             
  554.     if (lpStatData->feField[i].sWidth == 0) {
  555.         for (i = lpStatData->sNumFields - 1;  i > sField; i--)
  556.             rectOut->right -= lpStatData->feField[i].sWidth + 3;
  557.             
  558.         if (lpStatData->feField[sField].sWidth != 0)
  559.             rectOut->left = rectOut->right - lpStatData->feField[sField].sWidth;
  560.  
  561.     } else if (sField == lpStatData->sNumFields - 1)
  562.         rectOut->right = sRight;
  563.     else    
  564.         rectOut->right = rectOut->left + lpStatData->feField[i].sWidth - 3;
  565.         
  566.     return;
  567. }    
  568. //------------------------------------------------------------
  569. // DrawSBText - Displays text in a status bar field
  570. //------------------------------------------------------------ 
  571. void DrawSBText (HWND hWnd, char far *lpszText, INT sField) {
  572.     LPSTATUSBARDATA lpStatData;
  573.     RECT rect;
  574.  
  575.     lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0));
  576.     GetClientRect (hWnd, &rect);
  577.     GetFieldRect (lpStatData, sField, &rect, &rect);
  578.     DrawFieldText (lpStatData, hWnd, lpszText, &rect);
  579.     GlobalUnlock (GetWindowWord (hWnd, 0));
  580.     return;
  581. }    
  582. //------------------------------------------------------------
  583. // Draw3DRect - Routine that draws a 3D effect rectangle
  584. //------------------------------------------------------------ 
  585. void Draw3DRect (HDC hdc, HPEN hDPen, HPEN hLPen, RECT *rect) {
  586.     HPEN hOldPen;
  587.     //Start at bottom left, draw dark pen up and over top.
  588.     hOldPen = SelectObject (hdc, hDPen);
  589.     MoveTo (hdc, rect->left, rect->bottom);
  590.     LineTo (hdc, rect->left, rect->top);
  591.     LineTo (hdc, rect->right+1, rect->top);
  592.     //Start at bottom left, draw light pen over and up.
  593.     SelectObject (hdc, hLPen);
  594.     MoveTo (hdc, rect->left+1, rect->bottom);
  595.     LineTo (hdc, rect->right, rect->bottom);
  596.     LineTo (hdc, rect->right, rect->top);
  597.     SelectObject (hdc, hOldPen);
  598. }        
  599. //============================================================  
  600. // General Helper Routines 
  601. //============================================================  
  602.